﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;

[AddComponentMenu("PUEX/Affector/Physics/Gravity")]
public class PUEXGravityAffector : PUEXAffector {

	#region - Editable property
	public Vector3 gravityCenter;
	public string gravityCenterParamName = "";
	public float gravityRadius;
	public string gravityRadiusParamName = "";
	public float gravity;
	public string gravityParamName = "";
	public bool inWorldSpace;
	public bool applyOwnerScale;
	#endregion

	#region - Property
	protected Vector3 _center;
	protected float _radius;
	protected float _gravity;
	#endregion
	
	#region - Lifecycle
	public PUEXGravityAffector ()
	{
		gravityCenter = Vector3.zero;
		gravity = 1f;
		gravityRadius = 20f;
		inWorldSpace = true;
		applyOwnerScale = true;
	}
	#endregion
	
	#region - Update
	public override void preUpdate (float dt)
	{
		base.preUpdate (dt);

		_center = gravityCenter;
		_radius = gravityRadius;
		if (inWorldSpace) {
			if (ownerEmitter.keepLocal) {
				Matrix4x4 invMat = ownerEmitter.ownerParticleSystem.systemToWorldTransform.inverse;
				_center = invMat.MultiplyPoint(_center);
				_radius *= 1f / ownerEmitter.ownerParticleSystem.systemToWorldScale;
			}
		} else {
			if (!ownerEmitter.keepLocal) {
				_center = ownerEmitter.ownerParticleSystem.systemToWorldTransform.MultiplyPoint(_center);
				_radius *= ownerEmitter.ownerParticleSystem.systemToWorldScale;
			}
		}
		
		_gravity = gravity;
		if (applyOwnerScale) {
			_gravity *= ownerEmitter.ownerParticleSystem.systemToWorldScale;
		}
	}

	public override void update (float dt, PUEXParticle particle)
	{
		Vector3 distance = _center - particle.position;
		float length = distance.magnitude;
		if (length > 0f && length <= _radius)
		{
			float force = (_gravity * particle.mass) / length;
			particle.setVelocity(particle.velocity() + force * dt * distance.normalized);
		}
	}
	#endregion

	#region - Param property
	public override void updateParams (PUEXParticleSystem system)
	{
		Vector3 value3;
		if (system.getParamVec3 (gravityCenterParamName, out value3)) {
			gravityCenter = value3;
		}
		float value;
		if (system.getParamFloat (gravityRadiusParamName, out value)) {
			gravityRadius = value;
		}
		if (system.getParamFloat (gravityParamName, out value)) {
			gravity = value;
		}
	}
	#endregion
	
	#region - Draw
	public void OnDrawGizmos()
	{
		if (!enabled)
			return;

		Matrix4x4 defaultMatrix = Gizmos.matrix;
		if (inWorldSpace) {
			Gizmos.matrix = Matrix4x4.identity;
		} else {
			Gizmos.matrix = transform.parent.transform.localToWorldMatrix;
		}
		
		Color defaultColor = Gizmos.color;
		Gizmos.color = Color.yellow;

		Gizmos.DrawSphere (gravityCenter, 1f);
		Gizmos.DrawWireSphere (gravityCenter, gravityRadius);
		
		Gizmos.color = defaultColor;
		Gizmos.matrix = defaultMatrix;
	}
	#endregion

	#region - Serialization
	public override JsonData save (JsonData emitterData, JsonData systemData)
	{
		JsonData ret = base.save (emitterData, systemData);

		ret ["gravity_center"] = PUEXUtils.serializeVector3 (gravityCenter);
		ret ["gravity_center_param_name"] = gravityCenterParamName;
		ret ["gravity_radius"] = gravityRadius;
		ret ["gravity_radius_param_name"] = gravityRadiusParamName;
		ret ["gravity"] = gravity;
		ret ["gravity_param_name"] = gravityParamName;
		ret ["in_world_space"] = inWorldSpace;
		ret ["apply_owner_scale"] = applyOwnerScale;
		
		return ret;
	}
	#endregion

}
